#ifndef CB_FUN_HPP
#define CB_FUN_HPP
#include <unordered_map>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>

using std::string;
using std::to_string;

struct Equal
{
    bool operator()(const struct sockaddr_in k1, const struct sockaddr_in k2) const
    {
        return k1.sin_addr.s_addr == k2.sin_addr.s_addr;
    }
};

// static bool equal_to(struct sockaddr_in *k1, struct sockaddr_in *k2)
// {
//     return k1 == k2;
// }
// using equal = std::function<bool(struct sockaddr_in*,struct sockaddr_in*)>;

struct Hasher
{
    size_t operator()(const struct sockaddr_in key) const
    {
        return (size_t)key.sin_addr.s_addr;
    }
};

// static size_t Hash(struct sockaddr_in *key)
// {
//     return (size_t)key;
// }
// using hash = std::function<size_t(struct sockaddr_in*)>;
// using hash = std::function<size_t(struct sockaddr_in*)>;

class cbFun
{
private:
    /*
    * 这个函数用于将客户端的信息处理成字符串
    * 格式为:[ip:port]:message
    */
    string handle(const sockaddr_in header, string message)
    {
        string clientIP = inet_ntoa(header.sin_addr);
        uint16_t clientPort = ntohs(header.sin_port);
        string handled_string;
        handled_string = "[" + clientIP;
        handled_string += "-" + to_string(clientPort) + "]";
        handled_string += ":" + message;
        return handled_string;
    }

    /*
    * 这个函数用于将客户端的信息添加到client_map中，
    * key是客户端的地址，value是客户端的信息
    */
    void addUser(sockaddr_in header, string message)
    {
        string handled_message = handle(header, message);
        client_map[header] = handled_message;
    }

public:
    /*
     * 第一个参数是网络文件描述符
     * 第二个参数是网络数据结构
     * 第三个参数是要发送的信息
     */
    void operator()(int socketfd, sockaddr_in header, string message)
    {
        addUser(header, message);
        // std::cout << client_map.size() << std::endl;
        for (auto client : client_map)
        {
            string cb_message = client.second;
            size_t cb_message_len = client.second.size();
            for (auto boradcast : client_map)
            {
                socklen_t header_len = sizeof(boradcast.first);
                sendto(socketfd, cb_message.c_str(), cb_message_len, 0, (sockaddr *)&boradcast.first, header_len);
            }
        }

        // for(auto client:client_map)
        // {
        //     client.second.clear();
        // }
    }

    cbFun &operator*()
    {
        return *this;
    }

private:
    // std::unordered_map<struct sockaddr_in *, string> client_map;
    std::unordered_map<struct sockaddr_in, string, Hasher, Equal> client_map;
};

#endif